/*
 * Copyright 2009-2010 the original author or authors.
 *
 * Licensed under the Apache license, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.internna.iwebjtracker.hudson.services;

import java.net.URL;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.net.MalformedURLException;
import org.dom4j.Document;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Node;
import org.internna.iwebmvc.utils.CollectionUtils;
import org.internna.iwebjtracker.hudson.model.LastBuildData;
import org.internna.iwebjtracker.hudson.model.HudsonConfiguration;

import static org.internna.iwebmvc.utils.StringUtils.hasText;
import static org.internna.iwebjtracker.utils.UrlUtils.readUrl;

/**
 * Handles Hudson operations.
 *
 * @author Jose Noheda
 * @since 1.0
 */
public class HudsonManagerImpl implements HudsonManager {

    private static final Log logger = LogFactory.getLog(HudsonManagerImpl.class);

    /**
     * Checks the configuration and retrieves the required data using the Hudson's Remote API.
     *
     * @param configuration any
     * @return any
     */
    @Override public LastBuildData getInformationForLastBuild(HudsonConfiguration configuration) {
        LastBuildData data = null;
        if (configuration != null) {
            try {
                URL url = buildHudsonURL(configuration);
                data = parseBuild(readUrl(url));
                data.setUrl(url.toString());
            } catch (Exception ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Error getting Hudson metrics: " + ex.getMessage());
                }
            }
        }
        return data;
    }

    /**
     * Constructs a valid Hudson Remote API URL for a job.
     *
     * @param configuration any
     * @return any
     */
    protected URL buildHudsonURL(HudsonConfiguration configuration) throws MalformedURLException {
        StringBuilder url = new StringBuilder(configuration.getConnectionDetails().getUrl());
        url.append("/job/").append(configuration.getJobName()).append("/api/xml");
        return new URL(url.toString());
    }

    protected LastBuildData parseBuild(Document document) {
        LastBuildData data = new LastBuildData();
        data.setColor(getText(document, "/color"));
        String retrieved = getText(document, "/nextBuildNumber");
        data.setNumber(Integer.parseInt(hasText(retrieved) ? retrieved : "2") - 1);
        retrieved = getText(document, "/lastSuccessfulBuild/number");
        data.setSuccessful(Integer.parseInt(hasText(retrieved) ? retrieved : "0") == data.getNumber());
        retrieved = getText(document, "/lastStableBuild/number");
        data.setUnstable(data.isSuccessful() && hasText(retrieved) && (!retrieved.equals(getText(document, "/lastCompletedBuild/number"))));
        data.setMessages(getTexts(document, "/healthReport/description"));
        return data;
    }

    private String getText(Document document, String path) {
        try {
            return document.createXPath("/mavenModuleSet" + path).selectSingleNode(document).getText();
        } catch (Exception ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error getting Hudson metric[" + path + "]: " + ex.getMessage());
            }
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    private List<Map.Entry<String, String>> getTexts(Document document, String path) {
        List<Node> nodes = document.createXPath("/mavenModuleSet" + path).selectNodes(document);
        if (CollectionUtils.isNotEmpty(nodes)) {
            List<Map.Entry<String, String>> texts = new ArrayList<Map.Entry<String, String>>(nodes.size());
            for (Node node : nodes) {
                Map.Entry<String, String> entry = parseEntry(node.getText());
                if (entry != null) {
                    texts.add(entry);
                }
            }
            return texts;
        }
        return null;
    }

    protected Map.Entry<String, String> parseEntry(final String entry) {
        return hasText(entry) ? new Map.Entry<String, String>() {

            @Override public String getKey() {
                int pos = entry.indexOf(':');
                return pos < 0 ? entry : i18nHudson(entry.substring(0, pos));
            }

            @Override public String getValue() {
                int pos = entry.indexOf(':');
                return pos < 0 ? null : i18nHudson(entry.substring(pos + 1)).trim();
            }

            @Override public String setValue(String value) {
                return getValue();
            }
        } : null;
    }

    private String i18nHudson(String entry) {
        String i18n = entry;
        if (hasText(entry)) {
            if ("Build stability".equals(entry)) {
                i18n = "i18n.hudson.api.stability";
            }
            if ("Test Result".equals(entry)) {
                i18n = "i18n.hudson.api.result";
            }
            if ("No recent builds failed.".equals(entry)) {
                i18n = "i18n.hudson.api.nofails";
            }
            i18n = entry.replace("out of a total of", "out of");
        }
        return i18n;
    }

}
